/**
 * @Method mixins
 * @Description TODO
 * @Date 2021/1/21 16:35
 * @Created by HePing
 */

import { requestCache } from '../utils/request'
// eslint-disable-next-line
import toFormValues from './toFormValues'
import { isVal, getValueType, objectFormat } from '../utils'

export const VARS = {
  index: 1,
  keyword: ['style', 'type', 'class'],
  tagType: {
    CUSTOM: 'CUSTOM',
    PANEL: 'PANEL',
    FORM: 'FORM'
  },
  dataFrom: {
    local: 'local',
    interface: 'interface',
    function: 'function'
  }
}

export default {
  model: {
    prop: 'model'
  },
  props: {
    model: {
      type: Object,
      default() {
        return {}
      }
    },
    config: {
      type: Object,
      default() {
        return {
          formProps: {},
          rules: {},
          elements: []
        }
      }
    },
    loadDict: {
      type: Boolean,
      default: true
    },
    beforeCreated: {
      type: Function,
      default: null
    }
  },
  data() {
    return {
      fieldMap: {},
      virtualFieldMap: {}
    }
  },
  computed: {
    formProps() {
      return this.config && this.config.formProps || {}
    },
    elements: {
      get() {
        const getElements = (list) => {
          return (list || this.config && this.config.elements || []).map((o, i) => {
            ['slots', 'col', 'item', 'widget', 'dict', 'table'].forEach(k => {
              if (!o[k]) o[k] = {}
            });
            ['subWidgets', 'buttonGroup'].forEach(k => {
              if (!o[k]) o[k] = []
            })
            const field = 'virtualField' + i
            o.widget.virtualField = field
            // o.widget.field = o.widget.field || field
            // 缓存字段名的映射
            this.virtualFieldMap[o.widget.field] = field
            this.fieldMap[field] = o.widget.field
            if (o.subWidgets.length) {
              o.subWidgets = getElements(o.subWidgets)
            }
            return o
          })
        }
        return getElements()
      }
    },
    rules() {
      const o = {}
      Object.keys(this.config && this.config.rules).forEach(k => {
        o[this.virtualFieldMap[k]] = this.config.rules[k]
      })
      return o
    },
    formData: {
      get() {
        const getData = (elements) => {
          const o = {}
          const source = this.model;
          (elements || this.elements || []).forEach(({ widget, subWidgets }) => {
            const { virtualField, field, props, valueType } = widget
            const { defaultValue = '' } = props || {}
            let v = toFormValues.getFormValue(field, source)
            v = isVal(v) ? v : defaultValue
            const getValType = getValueType(valueType).fn
            o[virtualField] = isVal(v)
              ? v
              : (!getValType() ? undefined : getValType())
            if (subWidgets.length) {
              o.subWidgets = getData(subWidgets)
            }
          })
          return o
        }
        return getData()
      },
      set(o) {
        const source = JSON.parse(JSON.stringify(this.model))
        Object.keys(o).forEach(k => {
          toFormValues.setFormValue({ fieldPath: this.fieldMap[k], value: o[k], source })
        })
        // console.log('source', source)
        this.$emit('input', source)
      }
    }
  },
  async created() {
    if (this.beforeCreated) {
      await this.beforeCreated(this)
    }
    if (this.loadDict) {
      await this.fetchDict()
    }
  },
  methods: {
    spliceElement(field, o) {
      this.config.elements.some((item, i) => {
        if (item.widget.field === field) {
          this.config.elements.splice(i, 1, o || null)
          return true
        }
        return false
      })
    },
    find(fields) {
      if (!fields) return []
      return this.config.elements.filter(({ widget: { field } }) => fields.some(v => v === field))
    },
    hide() {
      this.find([].slice.call(arguments)).forEach(o => {
        if (!o) return
        o.hidden = true
        this.spliceElement(o.widget.field, o)
      })
      this.updateConfig()
    },
    show() {
      this.find([].slice.call(arguments)).forEach(o => {
        if (!o) return
        o.hidden = false
        this.spliceElement(o.widget.field, o)
      })
      this.updateConfig()
    },
    getElements(list) {
      return (list || this.config && this.config.elements || []).map((o, i) => {
        ['slots', 'col', 'item', 'widget', 'dict', 'table'].forEach(k => {
          if (!o[k]) o[k] = {}
        });
        ['subWidgets', 'buttonGroup'].forEach(k => {
          if (!o[k]) o[k] = []
        })
        const field = 'virtualField' + i
        o.widget.virtualField = field
        o.widget.field = o.widget.field || field
        // 缓存字段名的映射
        this.virtualFieldMap[o.widget.field] = field
        this.fieldMap[field] = o.widget.field
        if (o.subWidgets.length) {
          o.subWidgets = this.getElements(o.subWidgets)
        }
        return o
      })
    },
    async fetchDict() {
      const elements = this.config && this.config.elements
      if (!elements) return
      const d = []
      for (const o of elements) {
        const { type, fetch } = o.dict || {}
        if (type === 'INTERFACE' && fetch) {
          try {
            const { data } = await requestCache(fetch)
            o.dict.list = data || []
          } catch (e) {
            // e
          }
        }
        d.push(o)
      }
      this.config.elements = d
      this.updateConfig()
    },
    updateConfig() {
      this.$emit('update:config', this.config)
    },
    _on({ on, virtualField }) {
      if (!on) return
      const vm = this
      return {
        ...on,
        input: (value) => {
          const callback = () => vm.formData = { ...vm.formData, [virtualField]: value }
          if (typeof on.input === 'function') {
            on.input({ value, vm, callback })
          } else {
            callback()
          }
        }
      }
    }
  }
}
